package cn.catsdad.service.impl;

import cn.catsdad.base.page.PageBean;
import cn.catsdad.base.page.PageParam;
import cn.catsdad.base.service.impl.BaseCrudServiceImpl;
import cn.catsdad.dto.MenuDTO;
import cn.catsdad.dto.RoleDTO;
import cn.catsdad.dto.RoleMenuDTO;
import cn.catsdad.dto.RoleUserDTO;
import cn.catsdad.exception.BaseException;
import cn.catsdad.repository.RoleRepository;
import cn.catsdad.service.api.MenuService;
import cn.catsdad.service.api.RoleMenuService;
import cn.catsdad.service.api.RoleService;
import cn.catsdad.service.api.RoleUserService;
import cn.catsdad.util.StringUtil;
import cn.catsdad.util.TreeUtil;
import cn.catsdad.vo.TreeNodeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 角色service实现
 *
 * @author xuyonglong
 * @version V1.0 2023/4/13
 */
@Service
public class RoleServiceImpl extends BaseCrudServiceImpl<RoleDTO, Long, RoleRepository> implements RoleService {

    private MenuService menuService;
    private RoleMenuService roleMenuService;
    private RoleUserService roleUserService;

    @Override
    public void pageQuery(PageBean<RoleDTO> page, PageParam param) {
        page.setEntityName("RoleDTO r")
                .setQuery("select r");
        super.pageQuery(page, param);
    }

    @Override
    public RoleDTO queryById(Long aLong) {
        RoleDTO result = super.queryById(aLong);
        List<TreeNodeVO> treeNodeVOS = queryMenuTree(Collections.singleton(aLong));
        result.setMenus(treeNodeVOS);
        return result;
    }

    @Override
    @Transactional
    public RoleDTO save(RoleDTO entity) {
        validation(entity);
        return super.save(entity);
    }

    @Override
    @Transactional
    public void setUsers(RoleDTO role) {
        roleUserService.deleteByRoleIds(Collections.singleton(role.getId()));
        List<Long> userIds = role.getUserIds();
        List<RoleUserDTO> roleUsers = new ArrayList<>(userIds.size());
        for (Long userId : userIds) {
            RoleUserDTO roleUser = new RoleUserDTO();
            roleUser.setUserId(userId);
            roleUser.setRoleId(role.getId());
            roleUsers.add(roleUser);
        }
        if (StringUtil.isNotEmpty(roleUsers)) {
            roleUserService.saveAll(roleUsers);
        }
    }

    @Override
    @Transactional
    public void bingMenus(Long id, Collection<Long> menuIds) {
        roleMenuService.deleteByRoleIds(Collections.singleton(id));
        List<RoleMenuDTO> roleMenus = new ArrayList<>(menuIds.size());
        for (Long menuId : menuIds) {
            RoleMenuDTO roleMenu = new RoleMenuDTO();
            roleMenu.setMenuId(menuId);
            roleMenu.setRoleId(id);
            roleMenus.add(roleMenu);
        }
        if (StringUtil.isNotEmpty(roleMenus)) {
            roleMenuService.saveAll(roleMenus);
        }
    }

    /**
     * 根据角色获取菜单树形
     *
     * @param roleIds 角色id集合
     * @return 树形
     */
    @Override
    public List<TreeNodeVO> queryMenuTree(Collection<Long> roleIds) {
        List<TreeNodeVO> result = new ArrayList<>();
        List<MenuDTO> all = menuService.queryNormalMenus();
        Set<Long> hasPreMenus = roleMenuService.queryMenuIdsByRoles(roleIds);
        for (MenuDTO dtoMenu : all) {
            TreeNodeVO treeNodeVo = dtoMenu.initTreeNode();
            treeNodeVo.setValue(hasPreMenus.contains(dtoMenu.getId()));
            result.add(treeNodeVo);
        }
        return TreeUtil.buildTree(result, TreeUtil.Sort.ASC);
    }

    @Override
    @Transactional
    public void logicDeleteByIds(Collection<Long> longs) {
        if (StringUtil.isNotEmpty(longs)) {
            roleMenuService.deleteByRoleIds(longs);
            roleUserService.deleteByRoleIds(longs);
        }
        super.logicDeleteByIds(longs);
    }

    private void validation(RoleDTO entity) {
        Integer count = repository.countByNameAndIdNotAndIsDeletedFalse(entity.getName(), entity.getId());
        if (count > 0) {
            throw new BaseException("已存在当前角色！");
        }
    }

    @Autowired
    public void setMenuService(MenuService menuService) {
        this.menuService = menuService;
    }

    @Autowired
    public void setRoleMenuService(RoleMenuService roleMenuService) {
        this.roleMenuService = roleMenuService;
    }

    @Autowired
    public void setRoleUserService(RoleUserService roleUserService) {
        this.roleUserService = roleUserService;
    }
}
